package org.example;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonReader;
import org.apache.commons.collections4.CollectionUtils;
import org.example.dto.FieldInfo;

import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) throws IOException {
        Gson gson = new Gson();
        JsonReader reader = new JsonReader(new FileReader(Objects.requireNonNull(Main.class.getResource("/json/FieldInfo.json")).getFile()));
        JsonReader reader2 = new JsonReader(new FileReader(Objects.requireNonNull(Main.class.getResource("/json/Business.json")).getFile()));
        JsonArray jsonArray = gson.fromJson(reader, JsonArray.class);
        JsonObject input = gson.fromJson(reader2, JsonObject.class);
        reader2.close();
        reader.close();
        List<FieldInfo> fieldInfo = new ArrayList<>();
        jsonArray.forEach(json -> fieldInfo.add(gson.fromJson(json, FieldInfo.class)));
        System.out.println(transform(fieldInfo, input));
    }

    public static JsonObject transform(List<FieldInfo> fieldInfo, JsonObject input) {
        Map<String, FieldInfo> fieldInfoMap = fieldInfo.stream().collect(Collectors.toMap(FieldInfo::getField, t -> t));
        Set<String> diff = new HashSet<>(fieldInfoMap.keySet());
        JsonObject output = new JsonObject();
        for (Map.Entry<String, JsonElement> entry : input.entrySet()) {
            String inputKey = entry.getKey();
            FieldInfo targetField = fieldInfoMap.get(inputKey);
            String outputKey = targetField.getQaType();
            String outputValue = "";
            // has children
            if (CollectionUtils.isNotEmpty(targetField.getChildren())) {
                // children num > 1, add ';'
                if (output.get(outputKey) != null) {
                    outputValue += output.get(outputKey).getAsString() + ",";
                }
                boolean isArray = "array".equals(targetField.getFieldType());
                outputValue += wrapperValue(targetField, entry.getValue(), isArray);
            } else {
                // no children
                outputValue = targetField.getFieldName() + ":" + input.get(inputKey).getAsString();
            }
            output.addProperty(outputKey, outputValue);
            diff.remove(inputKey);
        }
        diff.forEach(key -> {
            output.addProperty(fieldInfoMap.get(key).getQaType(), "");
        });
        return output;
    }

    private static String wrapperValue(FieldInfo answerField, JsonElement input, boolean isArray) {
        String outputPrefix = answerField.getFieldName() + ":";
        Map<String, FieldInfo> childrenField = answerField.getChildren().stream().collect(Collectors.toMap(FieldInfo::getField, t -> t));
        String outputSuffix = wrapperChildren(input, childrenField, isArray);
        return outputPrefix + outputSuffix;
    }

    private static String wrapperChildren(JsonElement jsonElement, Map<String, FieldInfo> childrenField, boolean isArray) {
        StringBuilder resultSb = new StringBuilder();
        if (!isArray) {
            JsonObject jsonObject = jsonElement.getAsJsonObject();
            generateResult(resultSb, jsonObject, childrenField, false);
        } else {
            JsonArray input = jsonElement.getAsJsonArray();
            boolean multiAns = input.size() > 1;
            for (int i = 0; i < input.size(); i++) {
                JsonElement children = input.get(i);
                generateResult(resultSb, children, childrenField, multiAns);
            }
        }
        packContent(resultSb);
        return resultSb.toString();
    }

    private static void generateResult(StringBuilder resultSb, JsonElement jsonElement, Map<String, FieldInfo> fieldInfoMap, boolean multiAns) {
//        boolean multiKey = jsonElement.getAsJsonObject().size() > 1;
        for (Map.Entry<String, JsonElement> entry : jsonElement.getAsJsonObject().entrySet()) {
            resultSb.append(fieldInfoMap.get(entry.getKey()).getFieldName())
                    .append(":");
            boolean isJsonObj = entry.getValue().isJsonObject();
            if (isJsonObj) {
                StringBuilder subSb = new StringBuilder();
                generateResult(subSb, entry.getValue(), fieldInfoMap.get(entry.getKey()).getChildren().stream().collect(Collectors.toMap(FieldInfo::getField, t -> t)), multiAns);
                packContent(subSb);
                resultSb.append(subSb);
            } else {
                resultSb.append(entry.getValue().getAsString())
                        // 仅一层，json后也加了','看起来不是很合理
                        .append(",");
            }
        }

        if (multiAns) {
            resultSb.deleteCharAt(resultSb.length() - 1).append(";");
        }
    }

    private static void packContent(StringBuilder content) {
        content.insert(0, "[");
        content.append("]");
    }
}